/*
 * ## VERIFICAO DE FRASES E PALAVRAS SEQUENCIAL ##
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD 100
#define MAX_PHRASE 600

/*
 * Funcao definida para contagem dos valores ASCII da string
 * @input: string a ser verificada;
 * @return: soma valores dos caracteres da string;
 */
int contaASCII(char palavra[]){
    int soma=0, i;

    for (i=0; i<=strlen(palavra); i++){
        soma+= (int) palavra[i];

    }
return soma;

}

/*
 * Funcao para a verificacao de Numero Primo 
 * - Utilizacao do Algoritmo Crivo Erastotenes
 * @input: string a ser verificada;
 * @return: retorna se eh primo ou nao;
 */
int ehPrimo(char palavra[]) {
    int i, j, *vetor, z=-1, *primos, valor;

    valor = contaASCII(palavra);

    vetor = (int*) malloc (valor*sizeof(int));
    primos = (int*) malloc (valor*sizeof(int));

    for(i=2; i<=valor; i++){
        vetor[i]=i;
    }

    for(i=2; i<=valor; i++){
        if(vetor[i]==i){
            primos[++z] = i;
            for (j=2*i; j<=valor; j+=i) {
                vetor[j]=0; // removendo da lista
            }
        }
    }

    if(primos[z]==valor)
    {
        //printf("%d eh primo\n", valor);
	return 1;
    }

return 0;
}

/*
 * Funcao para verificacao de palindromo
 * @input: palavra a ser verificada, numero de caracteres da palavra
 * @return: retorna se eh palindromo ou nao 
 */
int palindromo(char *word, int NumCaracWord)
{
	int i,j,k,l;
	char buff[NumCaracWord];

	// palavras com numero par de caracteres
	if(NumCaracWord % 2 == 0)
	{
		i = (NumCaracWord / 2) - 1;
		for(j=0; j<=i;j++)
			buff[j] = word[j];

		buff[j] = '\0';
		//faz verificacao espelhada
		for(k = j,l=j-1; k<NumCaracWord;k++)
		{
			if(buff[l] != word[k])	//verifica o palindromo
				return 0; 
			else l--;
		}
		// caso nao encontra erro de espelhamento eh palindromo
		return 1;
	}
	// palavras com numero impar de caracteres
	else 
	{
		i = NumCaracWord / 2;
		for(j=0; j<i;j++)
			buff[j] = word[j];

		buff[j] = '\0';
		//faz verificacao espelhada
		for(k = j+1,l=j-1; k<NumCaracWord;k++)
		{
			if(buff[l] != word[k]) //verifica o palindromo
				return 0;
			else l--;
		}
		//caso nao encontra erro de espelhamento eh palindromo
		return 1;
	}
}


int main(int argc, char * argv[])
{
	FILE *fp;
	char word[MAX_WORD];
	char phrase[MAX_PHRASE];
	int i,j;
	int NumPhrases = 0;	// quantidade de Frases palindromos
	int NumWords = 0;	// quantidade de Palavras palindromos
	int NumCaracPhrase = 0;	// contagem de caracteres na frase
	int NumCaracWord = 0;   // contagem de caracteres na palavra
	int count_div = 0;	// contagem de divisao de blocos
	int NUM_BLOCK = 0;	// Divisao em Blocos para leitura do file
	size_t resultado;
	
	if(argc < 2)
	{
		printf("passe o arquivo de leitura como argumento!\n");
	}
	else
	{
		if(!(fp = fopen(argv[1],"r")))
		{
			printf("erro! Impossivel abrir o arquivo\n");
			return 0;
		}
		
		// calcula tamanho do arquivo para jogar em um buffer dinamico
		fseek(fp,0,SEEK_END);
		long tam_file = ftell(fp);
		rewind(fp);
	        
		NUM_BLOCK = 1;
		printf("tamfile= %ld\n",tam_file);
		long part_file = tam_file/NUM_BLOCK;
		printf("part_file = %ld\n",part_file);
		char *buffer;
		
		for(count_div = 0 ; count_div < NUM_BLOCK ; count_div++)
		{
		    // no ultimo bloco alocar mais espaco para ajuste
		    if(count_div == NUM_BLOCK-1)
		    {
			buffer = (char*)malloc(sizeof(char)*(part_file+51));
		    }
		    else
		    {
		        buffer = (char*)malloc(sizeof(char)*(part_file + 1));
		    }
		    
		    if(buffer != NULL)
		    {        
			    // no ultimo bloco ler mais dados
			    if(count_div == NUM_BLOCK-1)
			    {
			      resultado = fread(buffer,1,part_file+50,fp);
			    }
			    else
			    {
			      resultado = fread(buffer,1,part_file,fp);
			    }
			    buffer[resultado+1]='\0';
			      
				    for(i=0; i<resultado;i++)
				    {
				            // coloca os caracteres em letras minusculas	
					    buffer[i] = tolower(buffer[i]);
						
					     // == Phrase Verify == 
					     //add to phrase
					     
					      if(buffer[i] == '.' || buffer[i] == ';' || buffer[i] == '!' || buffer[i] == '?'
							  || buffer[i] =='\0' || buffer[i] == '\n') 
				             {
						phrase[NumCaracPhrase] = '\0';
						if(NumCaracPhrase > 1 && NumCaracPhrase < MAX_PHRASE)
						{
							if(palindromo(phrase,NumCaracPhrase))
							{
								//puts(phrase);
								NumPhrases++; 
							}
						}
						NumCaracPhrase = 0;
					     }
					     else if(isalnum(buffer[i]) && buffer[i]!=' ' && buffer[i] != '\t' && NumCaracPhrase < MAX_PHRASE)
					     {
						phrase[NumCaracPhrase] = buffer[i];
						NumCaracPhrase++;	
					     }

					    // == Word Verify ==
					    //verifica caractere de separacao de palavra
					    if(buffer[i] == ' ' || buffer[i]=='\n'
					    || buffer[i] == '\0' || buffer[i]=='\t')
					    {
					           						
						    word[NumCaracWord] = '\0'; 
						    // Verifica se a palavra em mais de 1 caractere
						    if(NumCaracWord > 1 && NumCaracWord < MAX_WORD)
						    {
							   /* == maior palavra com 603 caracteres ==
							   if(NumCaracWord > 100)
							   {
								printf("NumCaracWordteres=%d\n",NumCaracWord);
								puts(word);
								getchar();
							   }*/
							    // chama funcao palindromo para verificar palindromo de palavra
							    if(palindromo(word,NumCaracWord))
							    {
								if(ehPrimo(word))
								{
								   // puts(word);
								    NumWords++;
								}
							    }
						    }
						    //reinicia a contagem de caracteres da palavra
						    NumCaracWord = 0;
					    }
					    //ignora pontos e caracteres invalidos / verifica numero maximo de caracteres
					    else if(isalnum(buffer[i]) && NumCaracWord < MAX_WORD)
					    {
						    word[NumCaracWord] = buffer[i];
						    NumCaracWord++;
					    }
				    }
		    }
		    buffer = NULL;
		}
		printf("Quantidade de palindromos:\nFrases = %d\nPalavras = %d\n",NumPhrases,NumWords);
		fclose(fp);	//fecha o arquivo
		free(buffer);	//libera memoria do buffer
	}
	return 0;
}
